﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Perovich.GameObjects.Attributes;
using Microsoft.Xna.Framework;
using System.Diagnostics;

namespace Perovich.GameObjects.Components
{
    [ComponentDependency(typeof(Position2D))]
    [AutomaticProperty("XX", "Velocity2D.X", XmlSummary = "Gets or sets the X velocity of the entity.", XmlReturns = "A <see cref=\"System.Single\">float</see> that is the entity's X velocity.")]
    [AutomaticProperty("YY", "Velocity2D.Y", XmlSummary = "Gets or sets the Y velocity of the entity.", XmlReturns = "A <see cref=\"System.Single\">float</see> that is the entity's Y velocity.")]
    [AutomaticProperty("Velocity", "Velocity2D.Velocity", XmlSummary = "Gets or sets the velocity of the entity.", XmlReturns = "A <see cref=\"vector2\">Vector2</see> that is the entity's velocity.")]
    [AutomaticImport("Microsoft.Xna.Framework", false)]
    [AutomaticImport("Microsoft.Xna.Framework", true)]
    public sealed class Velocity2D : EntityComponent
    {
        Vector2 velocity;
        Position2D position;
        Bounds2D boun;
        Size2D size;
        public Velocity2D()
        {
            velocity = Vector2.Zero;
        }

        public float X
        {
            get
            {
                return velocity.X;
            }
            set
            {
                velocity = new Vector2(value, velocity.Y);
            }
        }

        public float Y
        {
            get
            {
                return velocity.Y;
            }
            set
            {
                velocity = new Vector2(velocity.X, value);
            }
        }

        public Vector2 Velocity
        {
            get
            {
                return velocity;
            }
            set
            {
                velocity = value;
            }
        }

        public override void Initialize()
        {
            position = Owner.Find<Position2D>();
            Owner.ComponentAdded += new EventHandler<EntityComponentEventArgs>(Owner_ComponentAdded);
            Owner.ComponentRemoved += new EventHandler<EntityComponentRemovedEventArgs>(Owner_ComponentRemoved);
            boun = Owner.Find<Bounds2D>();
            size = Owner.Find<Size2D>();
            UpdateOrder = Constants.VelocityUpdateOrder;
            base.Initialize();
        }

        void Owner_ComponentRemoved(object sender, EntityComponentRemovedEventArgs e)
        {
            if (e.Component is Bounds2D)
                boun = null;
            else if (e.Component is Size2D)
                size = null;
        }

        void Owner_ComponentAdded(object sender, EntityComponentEventArgs e)
        {
            Bounds2D b = e.Component as Bounds2D;
            Size2D s = e.Component as Size2D;
            if (b != null)
                boun = b;
            else if (s != null)
                size = s;
        }

        public override void Update(GameTime gameTime)
        {
            position.Position += Velocity * (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (boun != null)
            {
                switch (boun.BoundingStyle)
                {
                    case BoundingStyle.Bounce:
                        {
                            DoBounce();
                            break;
                        }
                    case BoundingStyle.Wrap:
                        {
                            DoWrap();
                            break;
                        }
                }
            }
            base.Update(gameTime);
        }


        private void DoWrap()
        {
            float width = size == null ? 0: size.Width;
            float height = size == null ? 0 : size.Height;

            float MaxX =
                 boun.Bounds.Right;
            float MinX = boun.Bounds.Left - width;
            float MaxY =
                boun.Bounds.Bottom;
            float MinY = boun.Bounds.Top - height;

            // Check for wrap.
            if (position.X > MaxX)
            {
                position.Position = new Vector2(MinX + position.X - MaxX, position.Y);
            }

            else if (position.X < MinX)
            {
                position.Position = new Vector2(MaxX + position.X - MinX, position.Y);
            }

            if (position.Y > MaxY)
            {
                position.Position = new Vector2(position.X, MinY + position.Y - MaxY);
            }

            else if (position.Y < MinY)
            {
                position.Position = new Vector2(position.X, MaxY + position.Y - MinY);
            }
        }

        private void DoBounce()
        {

            float width = size == null ? 0 : size.Width;
            float height = size == null ? 0 : size.Height;

            float MaxX =
                 boun.Bounds.Right - width;
            float MinX = boun.Bounds.Left;
            float MaxY =
                boun.Bounds.Bottom - height;
            float MinY = boun.Bounds.Top;

            // Check for bounce.
            if ((position.X > MaxX) && (Velocity.X > 0))
            {
                Velocity = new Vector2(-1 * Velocity.X, Velocity.Y);
            }

            else if ((position.X < MinX) && (Velocity.X < 0))
            {
                Velocity = new Vector2(-1 * Velocity.X, Velocity.Y);
            }

            if ((position.Y > MaxY) && (Velocity.Y > 0))
            {
                Velocity = new Vector2(Velocity.X, -1 * Velocity.Y);
            }

            else if ((position.Y < MinY) && (Velocity.Y < 0))
            {
                Velocity = new Vector2(Velocity.X, -1 * Velocity.Y);
            }
        }


    }
}
